package cn.db101.api.complex.component

import cn.db101.api.complex.utils.JsonUtils
import cn.db101.api.complex.component.Slf4j.Companion.log
import org.springframework.core.MethodParameter
import org.springframework.http.converter.HttpMessageConverter
import org.springframework.util.StreamUtils
import org.springframework.web.bind.support.WebDataBinderFactory
import org.springframework.web.context.request.NativeWebRequest
import org.springframework.web.method.support.ModelAndViewContainer
import org.springframework.web.servlet.mvc.method.annotation.AbstractMessageConverterMethodArgumentResolver
import sun.reflect.generics.reflectiveObjects.ParameterizedTypeImpl
import java.nio.charset.Charset
import javax.servlet.http.HttpServletRequest

@Slf4j
class RequestDataArgument(converters: List<HttpMessageConverter<*>?>?) :
    AbstractMessageConverterMethodArgumentResolver(converters) {

    override fun supportsParameter(methodParameter: MethodParameter): Boolean {
        return methodParameter.hasParameterAnnotation(RequestBodyData::class.java)
    }

    @Throws(Exception::class)
    override fun resolveArgument(
        parameter: MethodParameter,
        mavContainer: ModelAndViewContainer,
        webRequest: NativeWebRequest,
        binderFactory: WebDataBinderFactory
    ): Any? {
        val sr = webRequest.getNativeRequest(
            HttpServletRequest::class.java
        )

        val jsonNode = JsonUtils.MAPPER?.readTree(StreamUtils.copyToString(sr.inputStream, Charset.defaultCharset()))

        // 检验签名
        val sign = jsonNode?.get("sign")
        sr.setAttribute("sign", sign?.asText())

        val data = jsonNode?.get("data")

        log.info("request url => [{}] \r\nrequest content is => {}", sr.requestURL, data)

        if(parameter.parameterType.isAssignableFrom(List::class.java)) {
            // 找到对应的泛型类型
            val typeImpl = parameter.genericParameterType as ParameterizedTypeImpl

            val clazz = typeImpl.actualTypeArguments[0] as Class<*>

            return JsonUtils.toList(data.toString(), clazz)
        }

        return JsonUtils.fromJson(data.toString(), parameter.parameterType)
    }
}
